package com.ybear.ybcomponent.widget.damping.helper

import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.webkit.WebView
import android.widget.AbsListView
import android.widget.AdapterViewFlipper
import android.widget.ExpandableListView
import android.widget.HorizontalScrollView
import android.widget.ImageSwitcher
import android.widget.ScrollView
import android.widget.StackView
import android.widget.TextSwitcher
import android.widget.ViewAnimator
import androidx.core.view.NestedScrollingChild
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.ybear.ybcomponent.Utils
import com.ybear.ybcomponent.widget.ViewPager

/**
 * 控件是否可滑动帮助类
 */
open class ViewCanScrollHelper {
    // 缓存可以滚动的子 View，避免每次都遍历
    private val mChildScrollCache = arrayListOf<View>()
    // 滑动方向，默认为垂直方向
    @Orientation
    var orientation: Int = Orientation.VERTICAL

    // 是否是垂直方向滑动
    private val isVertical: Boolean
        get() = orientation == Orientation.VERTICAL

    /**
     * 更新可以滚动的子 View 缓存，递归遍历所有子 View，将可以滚动的 View 添加到缓存中
     * @param view 要检查的 View
     */
    open fun updateChildScrollCache(view: View?) {
        if (view == null || view !is ViewGroup) return
        // 存储当前 View 的滚动状态
        if ( !mChildScrollCache.contains( view ) ) mChildScrollCache.add( view )
        // 如果是 ViewGroup，递归更新子 View 的滚动状态
        for ( i in 0 until view.childCount ) {
            // 递归调用自身，检查所有子 View
            updateChildScrollCache( view.getChildAt( i ) )
        }
    }

    /**
     * 检查是否存在可以滚动的子控件，优先检查触摸点所在的子 View 是否可以滚动，
     * 如果不能滚动，则检查缓存的可以滚动的子 View 列表
     * @param view 要检查的 View
     * @param isPullDown 是否是下拉
     * @param event 触摸事件
     * @return 是否存在可以滚动的子控件
     */
    open fun canAnyChildScroll(view: View, isPullDown: Boolean, event: MotionEvent): Boolean {
        if (view !is ViewGroup) return false

        // 优先检查触摸点所在的子 View 是否可以滚动
        for (i in 0 until view.childCount) {
            val child = view.getChildAt(i)
            if (!Utils.isPointInView(child, event)) continue
            // 如果子 View 可以滚动，则直接返回 true
            if (canChildScroll(child, isPullDown) > 0) {
                return true
            }
        }

        // 如果触摸点所在的子 View 不能滚动，则检查缓存的可以滚动的子 View 列表
        mChildScrollCache.forEach {
            if ((isVertical && isPullDown && it.canScrollVertically(-1)) ||
                (isVertical && !isPullDown && it.canScrollVertically(1)) ||
                (!isVertical && isPullDown && it.canScrollHorizontally(-1)) ||
                (!isVertical && !isPullDown && it.canScrollHorizontally(1))
            ) {
                return true
            }
        }

        // 如果所有子 View 都不能滚动，则返回 false
        return false
    }

    /**
     * 判断子 View 是否可以滚动
     *
     * @param view       需要判断的 View
     * @param isPullDown 是否是下拉操作
     * @return 1 表示可以滚动，0 表示不能滚动，-1 表示不支持该 View 类型的判断
     */
    open fun canChildScroll(view: View, isPullDown: Boolean): Int {
        return when (view) {
            is RecyclerView, is ViewPager, is ViewPager2, is NestedScrollingChild, is WebView ->
                canScrollVerticallyOrHorizontally(view, isPullDown)
            is ScrollView -> canScrollView(view, isPullDown)
            is HorizontalScrollView -> canHorizontalScrollView(view, isPullDown)
            is ExpandableListView -> canExpandableListView(view, isPullDown)
            is AbsListView -> canAbsListView(view, isPullDown)
            is AdapterViewFlipper, is StackView, is TextSwitcher, is ImageSwitcher, is ViewAnimator ->
                canViewFlipperLike(view, isPullDown)
            else -> -1
        }
    }

    /**
     * 判断可以使用 canScrollVertically/canScrollHorizontally 判断的 View 是否可以滚动
     */
    protected open fun canScrollVerticallyOrHorizontally(view: View, isPullDown: Boolean): Int {
        return if ( isVertical ) {
            if (view.canScrollVertically(if (isPullDown) -1 else 1)) 1 else 0
        } else {
            if (view.canScrollHorizontally(if (isPullDown) -1 else 1)) 1 else 0
        }
    }

    /**
     * 判断 ScrollView 是否可以滚动
     */
    protected open fun canScrollView(view: ScrollView, isPullDown: Boolean): Int {
        return if (isVertical) {
            if (isPullDown) {
                if (view.scrollY > 0) 1 else 0
            } else {
                if (view.scrollY < view.getChildAt(0).height - view.height) 1 else 0
            }
        } else {
            if (isPullDown) {
                if (view.scrollX > 0) 1 else 0
            } else {
                if (view.scrollX < view.getChildAt(0).width - view.width) 1 else 0
            }
        }
    }

    /**
     * 判断 HorizontalScrollView 是否可以滚动
     */
    protected open fun canHorizontalScrollView(view: HorizontalScrollView, isPullDown: Boolean): Int {
        val canScroll = if (isPullDown) {
            view.scrollX > 0
        } else {
            view.scrollX < view.getChildAt(0).width - view.width
        }
        return if (canScroll) 1 else 0
    }

    /**
     * 判断 ExpandableListView 是否可以滚动
     */
    protected open fun canExpandableListView(view: ExpandableListView, isPullDown: Boolean): Int {
        return if (isPullDown) {
            if (view.firstVisiblePosition == 0 && view.getChildAt(0)?.top == view.getTop()) {
                0 // 已经在顶部
            } else {
                1 // 可以下拉刷新
            }
        } else {
            if (view.lastVisiblePosition == view.count - 1 &&
                view.getChildAt(view.childCount - 1)?.bottom == view.getBottom()
            ) {
                0 // 已经在底部
            } else {
                1 // 可以上拉加载
            }
        }
    }

    /**
     * 判断 AbsListView 是否可以滚动
     */
    protected open fun canAbsListView(view: AbsListView, isPullDown: Boolean): Int {
        return if (isVertical) {
            if (isPullDown) {
                if (view.firstVisiblePosition > 0 || view.getChildAt(0).top < view.paddingTop) 1 else 0
            } else {
                if (view.lastVisiblePosition < view.count - 1 ||
                    view.getChildAt(view.childCount - 1).bottom > view.height - view.paddingBottom
                ) 1 else 0
            }
        } else {
            if (isPullDown) {
                if (view.firstVisiblePosition > 0 ||
                    view.getChildAt(0).left < view.paddingLeft
                ) 1 else 0
            } else {
                if (view.lastVisiblePosition < view.count - 1 ||
                    view.getChildAt(view.childCount - 1).right > view.width - view.paddingRight
                ) 1 else 0
            }
        }
    }

    /**
     * 判断可以使用 displayedChild 判断的 View 是否可以滚动
     */
    protected open fun canViewFlipperLike(view: View, isPullDown: Boolean): Int {
        if (view is ViewAnimator) {
            return if (isPullDown) {
                if (view.displayedChild == 0) 0 else 1
            } else {
                if (view.displayedChild == view.childCount - 1) 0 else 1
            }
        }
        return -1 // 如果不是 ViewAnimator 或其子类，返回 -1
    }
}